package com.itheima.app.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.itheima.app.interceptor.UserHolder;
import com.itheima.autoconfig.face.AipFaceTemplate;
import com.itheima.autoconfig.huanxin.HuanXinTemplate;
import com.itheima.autoconfig.oss.OssTemplate;
import com.itheima.autoconfig.sms.SmsTemplate;
import com.itheima.domain.db.Log;
import com.itheima.domain.db.User;
import com.itheima.domain.db.UserInfo;
import com.itheima.domain.vo.UserInfoVo;
import com.itheima.service.db.UserInfoService;
import com.itheima.service.db.UserService;
import com.itheima.util.ConstantUtil;
import com.itheima.util.JwtUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service // 封装controller的逻辑代码
public class UserManger {

    @DubboReference //远程注入对象
    private UserService userService;
    //保存用户
    public Long save(User user) {
        //注册的时候 很多手机端 是不写密码的 而写死密码
        user.setPassword("123456"); //暂时写死
        Long id = userService.save(user);
        return id;
    }

    //根据手机号查询用户
    public User findByPhone(String phone) {
        return userService.findByPhone(phone);
    }

    @Autowired
    private SmsTemplate smsTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //发送短信验证码
    public void sendSmsLoginOrRegister(String phone) {
        //1.发送验证码
        //String code = RandomUtil.randomNumbers(6); //生成6位数字
        //smsTemplate.sendSms(phone, code);
        //TODO 以后需要修改成动态验证码   标记  定位用的
        String code = "123456"; //测试阶段写死 怕浪费钱
        //2.将数据存入到redis
        stringRedisTemplate.opsForValue().set(ConstantUtil.SMS_CODE+phone , code  ,5, TimeUnit.MINUTES);
    }


    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 1.先从redis中获得验证码 进行比较验证码 如果正确 继续
     * 2.根据手机号进行数据库查询
     * 3.1 查询到了 执行登录请求
     * 3.2 查询不到 执行注册请求
     * 4.不管是注册还是登录都要生成token 返回给app端
     * 5.将token存入到redis
     * 6.让验证码失效
     */
    public ResponseEntity loginOrRegister(String phone, String verificationCode) {
        //1.先从redis中获得验证码 进行比较验证码 如果正确 继续
        String redisCode = stringRedisTemplate.opsForValue().get(ConstantUtil.SMS_CODE + phone);
        if(!StrUtil.equals(verificationCode ,redisCode )){
            return ResponseEntity.status(500).body("验证码错误"); //抛出异常
        }


        //2.根据手机号进行数据库查询
        User user = userService.findByPhone(phone);
        //定义用户id
        Long userId = null;
        boolean isNew = false;
        if(user == null){
            //3.2 查询不到 执行注册请求
            user = new User();
            user.setMobile(phone);
            userId = this.save(user); //返回用户的id
            user.setId(userId); //重新赋值一下id
            isNew = true;//新用户

            user.setHxUser("HX"+userId);
            user.setHxPassword("123456");
            //注册环信用户
            huanXinTemplate.register("HX"+userId);

            //记录日志 -注册日志
            Log log = new Log();
            log.setUserId( userId );//操作人
            log.setPlace( "北京顺义" ); //操作地点  读取mongo
            log.setEquipment("小米9");//操作设备
            log.setType("0102");//操作类型  注册
            log.setLogTime(DateUtil.formatDate(new Date()));//操作时间
            //发送消息
            rabbitTemplate.convertAndSend("tanhua.log" , log);

        }else{
            //3.1 查询到了 执行登录请求
            userId = user.getId(); //将登录的用户id 赋值
            isNew= false;//已经存在用户

            //查询用户是否被冻结
            Boolean freeze = this.findFreeze("1", user.getId());
            System.err.println(freeze);
            if (freeze){
                return ResponseEntity.status(500).body("用户已被冻结"); //抛出异常
            }
            //记录日志 -登录日志
            Log log = new Log();
            log.setUserId( userId );//操作人
            log.setPlace( "北京顺义" ); //操作地点  读取mongo
            log.setEquipment("小米9");//操作设备
            log.setType("0101");//操作类型  登录
            log.setLogTime(DateUtil.formatDate(new Date()));//操作时间
            //发送消息
            rabbitTemplate.convertAndSend("tanhua.log" , log);

        }

        //4.不管是注册还是登录都要生成token 返回给app端
        Map tokenMap = new HashMap<>();
        tokenMap.put("id" , userId);
        tokenMap.put("mobile" , user.getMobile() );
        String token = JwtUtil.createToken(tokenMap);
        //5.将token存入到redis
        String json = JSON.toJSONString(user); //将用户对象转换成了json存入到redis
        stringRedisTemplate.opsForValue().set( ConstantUtil.USER_TOKEN +  token , json , 7 ,TimeUnit.DAYS );
        //6.让验证码失效  删除redis缓存中的验证码
        stringRedisTemplate.delete(ConstantUtil.SMS_CODE + phone);


        //7.构建返回值
        // token : 当前登录令牌 isNew : 是不是新用户 当前此次请求是登录还是注册的 (前端根据这个值跳转登录或者注册页面)

        Map returnMap = new HashMap();
        returnMap.put("token" , token);
        returnMap.put("isNew" , isNew);
        return ResponseEntity.ok(returnMap);
    }


    @DubboReference
    private UserInfoService userInfoService;
    //完善资料
    //前端有传入数据跟数据库数据不是完全匹配
    public void saveUserInfo(UserInfo userInfo, String token) {
        //1.完善前端没有传入的数据(为了数据库表中数据的完整性添加)
        userInfo.setIncome("50");
        userInfo.setEducation("本科");
        userInfo.setProfession("无业");
        userInfo.setMarriage(0);
        userInfo.setTags("单身,本科,年龄相仿");
        userInfo.setAge(20);
        //2.赋值id
        //User user = findUserByToken(token);  //findUserByToken 解析token
        User user = UserHolder.get();  //findUserByToken 解析token
        userInfo.setId( user.getId() ); //将数据存入了token中
        //3.保存对象
        userInfoService.save(userInfo);
    }

    /**
     * 解析token
     * @param token
     * @return
     */
    /*private User findUserByToken(String token) {
        //String json = JSON.toJSONString(user); //将用户对象转换成了json存入到redis
        //stringRedisTemplate.opsForValue().set( ConstantUtil.USER_TOKEN +  token , json , 7 ,TimeUnit.DAYS );

        String json = stringRedisTemplate.opsForValue().get(ConstantUtil.USER_TOKEN + token);
        //解析json即可
        if(json != null){
            User user = JSON.parseObject(json, User.class); //将json转换成 user对象
            return user;
        }
        //续期操作 -- 一会解释 统一token的时候解释
        stringRedisTemplate.opsForValue().set( ConstantUtil.USER_TOKEN +  token , json , 7 ,TimeUnit.DAYS );
        return null;
    }*/

    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private AipFaceTemplate aipFaceTemplate;
    /**
     * 更新用户头像
     * 1.人脸识别
     * 2.上传到oss的平台上
     * 3.解析id
     * 4.根据id和 上传的oss平台返回的图片的路径 修改到数据库
     */
    public void updateUserInfoHead(MultipartFile headPhoto, String token) throws IOException {
        if(headPhoto!=null && headPhoto.getSize()>0){//图片一定存在
            //1.人脸识别
            boolean flag = aipFaceTemplate.detect(headPhoto.getBytes());
            if(!flag){
                throw new RuntimeException("人脸识别不通过");
            }
            //2.上传到oss的平台上
            String picPath = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
            //3.解析id
            //User user = findUserByToken(token);
            User user = UserHolder.get();
            //4.根据id和 上传的oss平台返回的图片的路径 修改到数据库
            UserInfo userInfo = new UserInfo();
            userInfo.setId(  user.getId()  );//赋值id
            userInfo.setAvatar(picPath); //头像
            userInfo.setCoverPic( picPath ); //朋友圈背景图片
            userInfoService.update(userInfo);
            //url = 读取昨天的配置  https://ip:端口/users
            // axios.get(url  , 参数)
        }
    }

    /**
     * 根据用户的id查询用户对象
     * @param token
     * @return
     */
    public ResponseEntity findUserInfoById(String userId, String token) {
        UserInfo userInfo = null;
        if(userId != null){  //如果传递了 userId 根据userId查询
            userInfo = userInfoService.findByUserId(Long.valueOf(userId));
        }else{
            //1.解析token
            //User user = findUserByToken(token);
            User user = UserHolder.get();
            //2.根据user获得userInfo
            userInfo = userInfoService.findByUserId(user.getId());
        }

        //3.核心  将userInfo 转换成 userInfoVo
        UserInfoVo vo = new UserInfoVo();
        //参数1: 源对象(数据的来源)   参数2 : 目标对象(去的地方)
        //要求: 字段名称一致 自动封装  如果字段不一致 手动封装
        BeanUtil.copyProperties(userInfo , vo);

        return ResponseEntity.ok(vo);
    }

    //修改用户资料
    public ResponseEntity updateUserInfo(UserInfo userInfo, String token) {
        //1.解析token获得id
        //User user = findUserByToken(token);
        User user = UserHolder.get();
        //2.赋值id
        userInfo.setId( user.getId() );
        //3.修改数据
        userInfoService.update(userInfo);
        return ResponseEntity.ok(null);
    }
    //查看用户被冻结
    public Boolean findFreeze(String range,Long userId){
        Boolean isfreeze = stringRedisTemplate.hasKey(ConstantUtil.FREEZE_TIME + userId);
        String freezeRange = stringRedisTemplate.opsForValue().get(ConstantUtil.FREEZE_RANGE + userId);
        boolean isrange = StrUtil.equals(range, freezeRange);
        if (isfreeze&isrange){
            return true;
        }
        return false;
    }
}
